//
//  NSArray+BPCrash.m
//  BPCrashDemo
//
//  Created by SiYugui on 2019/12/18.
//  Copyright © 2019年 SiYugui. All rights reserved.
//

#import "NSArray+BPCrash.h"
#import "NSObject+BPSwizzle.h"
#import "BPCrashLog.h"

@implementation NSArray (BPCrash)

+ (void)avoidArrayCrashExchangeMethod{
    
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        
        ///class method
        //instance array method exchange
        [self exchangeInstanceMethod:@selector(arrayWithObjects:count:) method2:@selector(__arrayWithObjects:count:)];
        
        ///instance method
        Class __NSArray = NSClassFromString(@"NSArray");
        Class __NSArrayI = NSClassFromString(@"__NSArrayI");
        Class __NSSingleObjectArrayI = NSClassFromString(@"__NSSingleObjectArrayI");
        Class __NSArray0 = NSClassFromString(@"__NSArray0");
        
        //objectsAtIndexes:
        [self exchangeInstanceMethod:__NSArray method1:@selector(objectsAtIndexes:) method2:@selector(__objectsAtIndexes:)];
        
        //objectAtIndex:
        [self exchangeInstanceMethod:__NSArrayI method1:@selector(objectAtIndex:) method2:@selector(__NSArrayIObjectAtIndex:)];
        
        [self exchangeInstanceMethod:__NSSingleObjectArrayI method1:@selector(objectAtIndex:) method2:@selector(__NSSingleObjectArrayIObjectAtIndex:)];
        
        [self exchangeInstanceMethod:__NSArray0 method1:@selector(objectAtIndex:) method2:@selector(__NSArray0ObjectAtIndex:)];
        
        //objectAtIndexedSubscript:
        if (@available(iOS 11.0, *)) {
            [self exchangeInstanceMethod:__NSArrayI method1:@selector(objectAtIndexedSubscript:) method2:@selector(__objectAtIndexedSubscript:)];
        }
        
        //getObjects:range:
        [self exchangeInstanceMethod:__NSArray method1:@selector(getObjects:range:) method2:@selector(__getObjects:range:)];
        
        [self exchangeInstanceMethod:__NSSingleObjectArrayI method1:@selector(getObjects:range:) method2:@selector(__NSSingleObjectArrayIGetObjects:range:)];
        
        [self exchangeInstanceMethod:__NSArrayI method1:@selector(getObjects:range:) method2:@selector(__NSArrayIGetObjects:range:)];
        
    });
}

#pragma mark - instance array

+(instancetype)__arrayWithObjects:(id  _Nonnull const [])objects count:(NSUInteger)cnt{
    id instance = nil;
    
    @try {
        instance = [self __arrayWithObjects:objects count:cnt];
    }
    @catch (NSException *exception) {
        
        NSString *defaultToDo = @"This framework default is to remove nil object and instance a array.";
        [BPCrashLog noteErrorWithException:exception attachedToDo:defaultToDo];
        
        //以下是对错误数据的处理，把为nil的数据去掉,然后初始化数组
        NSInteger newObjsIndex = 0;
        id  _Nonnull __unsafe_unretained newObjects[cnt];
        
        for (int i = 0; i < cnt; i++) {
            if (objects[i] != nil) {
                newObjects[newObjsIndex] = objects[i];
                newObjsIndex++;
            }
        }
        instance = [self __arrayWithObjects:newObjects count:newObjsIndex];
    }
    @finally {
        return instance;
    }
}


#pragma mark - objectAtIndexedSubscript:
-(id)__objectAtIndexedSubscript:(NSUInteger)idx{
    id object = nil;
    
    @try {
        object = [self __objectAtIndexedSubscript:idx];
    }
    @catch (NSException *exception) {
        NSString *defaultToDo = BPCrashDefaultReturnNil;
        [BPCrashLog noteErrorWithException:exception attachedToDo:defaultToDo];
    }
    @finally {
        return object;
    }
}

#pragma mark - objectAtIndexes

-(NSArray *)__objectsAtIndexes:(NSIndexSet *)indexes{
    NSArray *returnArray = nil;
    @try {
        returnArray = [self __objectsAtIndexes:indexes];
    } @catch (NSException *exception) {
        NSString *defaultToDo = BPCrashDefaultReturnNil;
        [BPCrashLog noteErrorWithException:exception attachedToDo:defaultToDo];
        
    } @finally {
        return returnArray;
    }
}

#pragma mark - objectAtIndex

///__NSArrayI:

- (id)__NSArrayIObjectAtIndex:(NSUInteger)index {
    id object = nil;
    
    @try {
        object = [self __NSArrayIObjectAtIndex:index];
    }
    @catch (NSException *exception) {
        NSString *defaultToDo = BPCrashDefaultReturnNil;
        [BPCrashLog noteErrorWithException:exception attachedToDo:defaultToDo];
    }
    @finally {
        return object;
    }
}

///__NSSingleObjectArrayI

- (id)__NSSingleObjectArrayIObjectAtIndex:(NSUInteger)index {
    id object = nil;
    
    @try {
        object = [self __NSSingleObjectArrayIObjectAtIndex:index];
    }
    @catch (NSException *exception) {
        NSString *defaultToDo = BPCrashDefaultReturnNil;
        [BPCrashLog noteErrorWithException:exception attachedToDo:defaultToDo];
    }
    @finally {
        return object;
    }
}

///__NSArray0

- (id)__NSArray0ObjectAtIndex:(NSUInteger)index {
    id object = nil;
    
    @try {
        object = [self __NSArray0ObjectAtIndex:index];
    }
    @catch (NSException *exception) {
        NSString *defaultToDo = BPCrashDefaultReturnNil;
        [BPCrashLog noteErrorWithException:exception attachedToDo:defaultToDo];
    }
    @finally {
        return object;
    }
}

#pragma mark - getObjects:range:

-(void)__getObjects:(__unsafe_unretained id  _Nonnull [])objects range:(NSRange)range{
    @try {
        [self __getObjects:objects range:range];
    } @catch (NSException *exception) {
        
        NSString *defaultToDo = BPCrashDefaultReturnIgnore;
        [BPCrashLog noteErrorWithException:exception attachedToDo:defaultToDo];
        
    } @finally {
        
    }
}

///__NSSingleObjectArrayI  getObjects:range:
- (void)__NSSingleObjectArrayIGetObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
    
    @try {
        [self __NSSingleObjectArrayIGetObjects:objects range:range];
    } @catch (NSException *exception) {
        
        NSString *defaultToDo = BPCrashDefaultReturnIgnore;
        [BPCrashLog noteErrorWithException:exception attachedToDo:defaultToDo];
        
    } @finally {
        
    }
}

///__NSArrayI  getObjects:range:
- (void)__NSArrayIGetObjects:(__unsafe_unretained id  _Nonnull *)objects range:(NSRange)range {
    
    @try {
        [self __NSArrayIGetObjects:objects range:range];
    } @catch (NSException *exception) {
        
        NSString *defaultToDo = BPCrashDefaultReturnIgnore;
        [BPCrashLog noteErrorWithException:exception attachedToDo:defaultToDo];
        
    } @finally {
        
    }
}


@end
